#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include "esp_err.h"
#include "esp_log.h"
#include "esp_sleep.h"
#include "nvs_flash.h"
#include "driver/gpio.h"
#include "esp_bt.h"
#include "esp_bt_main.h"
#include "esp_gap_ble_api.h"
#include "esp_gatts_api.h"
#include "esp_bluedroid.h"

// -------------------------- 配置参数 --------------------------
// BLE 设备名称
#define DEVICE_NAME               "ESP32-LP-BLE"
// 自定义服务和特征值 UUID（16-bit）
#define ENV_SERVICE_UUID          0x181A  // 环境监测服务（标准UUID）
#define TEMP_CHAR_UUID            0x2A6E  // 温度特征值（标准UUID）
#define CONFIG_CHAR_UUID          0xFFF0  // 配置特征值（自定义，用于设置采样间隔）
// 深度睡眠时长（单位：ms，默认 10 秒，可通过 BLE 配置修改）
#define DEFAULT_SLEEP_DURATION    10000
// NVS 存储键名
#define NVS_NAMESPACE             "ble_config"
#define NVS_SLEEP_KEY             "sleep_ms"

// -------------------------- 全局变量 --------------------------
static const char *TAG = "LP_BLE_EXAMPLE";
static esp_gatt_if_t gatts_if = ESP_GATT_IF_NONE;  // GATT 接口句柄
static uint16_t conn_id = 0;                       // 连接 ID
static uint32_t sleep_duration = DEFAULT_SLEEP_DURATION;  // 睡眠时长
static float temperature = 25.0f;                  // 模拟温度数据
static uint8_t temp_data[4];                       // 温度数据（浮点转4字节）

// -------------------------- NVS 操作 --------------------------
// 从 NVS 读取睡眠时长配置
static void nvs_load_sleep_config() {
    nvs_handle_t handle;
    esp_err_t ret = nvs_open(NVS_NAMESPACE, NVS_READONLY, &handle);
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "NVS open failed, use default sleep duration");
        return;
    }
    // 读取配置（默认使用 DEFAULT_SLEEP_DURATION）
    ret = nvs_get_u32(handle, NVS_SLEEP_KEY, &sleep_duration);
    if (ret != ESP_OK) {
        ESP_LOGW(TAG, "NVS read failed, use default");
        sleep_duration = DEFAULT_SLEEP_DURATION;
    } else {
        ESP_LOGI(TAG, "Loaded sleep duration: %ums", sleep_duration);
    }
    nvs_close(handle);
}

// 向 NVS 保存睡眠时长配置
static void nvs_save_sleep_config() {
    nvs_handle_t handle;
    esp_err_t ret = nvs_open(NVS_NAMESPACE, NVS_READWRITE, &handle);
    if (ret != ESP_OK) {
        ESP_LOGE(TAG, "NVS open failed, can't save config");
        return;
    }
    ret = nvs_set_u32(handle, NVS_SLEEP_KEY, sleep_duration);
    if (ret == ESP_OK) {
        nvs_commit(handle);  // 提交写入
        ESP_LOGI(TAG, "Saved sleep duration: %ums", sleep_duration);
    } else {
        ESP_LOGE(TAG, "NVS save failed");
    }
    nvs_close(handle);
}

// -------------------------- BLE GATT 回调 --------------------------
static void gatts_event_handler(esp_gatts_cb_event_t event, esp_gatt_if_t gatt_if,
                               esp_ble_gatts_cb_param_t *param) {
    switch (event) {
        // GATT 应用注册完成
        case ESP_GATTS_REG_EVT:
            gatts_if = gatt_if;
            ESP_LOGI(TAG, "GATT app registered, if: %d", gatts_if);
            // 创建环境监测服务
            esp_ble_gatts_create_service(gatts_if, ESP_GATT_UUID_DECLARE_16(ENV_SERVICE_UUID), 4);
            break;

        // 服务创建完成，添加特征值
        case ESP_GATTS_CREATE_EVT: {
            esp_gatt_service_handle_t service_handle = param->create.service_handle;
            ESP_LOGI(TAG, "Service created, handle: %d", service_handle);

            // 1. 添加温度特征值（可读 + 可通知）
            esp_ble_gatts_char_prop_t temp_prop = ESP_GATT_CHAR_PROP_READ | ESP_GATT_CHAR_PROP_NOTIFY;
            esp_ble_gatt_char_def_t temp_char = {
                .uuid = ESP_GATT_UUID_DECLARE_16(TEMP_CHAR_UUID),
                .properties = temp_prop,
                .perm = ESP_GATT_PERM_READ,
                .val_len = sizeof(temp_data),
                .val = temp_data,
            };
            // 添加客户端配置描述符（用于控制通知）
            esp_ble_gatt_descr_def_t cccd = {
                .uuid = ESP_GATT_UUID_DECLARE_16(ESP_GATT_UUID_CLIENT_CHAR_CFG),
                .perm = ESP_GATT_PERM_READ | ESP_GATT_PERM_WRITE,
                .max_len = 2,
                .val = NULL,
            };
            esp_ble_gatts_add_char(service_handle, &temp_char, &cccd);

            // 2. 添加配置特征值（可写，用于修改睡眠间隔）
            esp_ble_gatts_char_prop_t config_prop = ESP_GATT_CHAR_PROP_WRITE;
            esp_ble_gatt_char_def_t config_char = {
                .uuid = ESP_GATT_UUID_DECLARE_16(CONFIG_CHAR_UUID),
                .properties = config_prop,
                .perm = ESP_GATT_PERM_WRITE,
                .val_len = 4,  // 4字节存储 uint32_t（睡眠时长 ms）
                .val = (uint8_t*)&sleep_duration,
            };
            esp_ble_gatts_add_char(service_handle, &config_char, NULL);

            // 启动服务
            esp_ble_gatts_start_service(service_handle);
            break;
        }

        // 处理读请求（客户端读取温度）
        case ESP_GATTS_READ_EVT: {
            ESP_LOGI(TAG, "Read temperature request");
            // 模拟更新温度数据（实际场景中替换为传感器读取）
            temperature += 0.1f;
            memcpy(temp_data, &temperature, sizeof(temperature));
            // 响应读请求
            esp_ble_gatts_send_response(gatts_if, param->read.conn_id, param->read.trans_id,
                                       ESP_GATT_OK, &(esp_gatt_rsp_t){
                                           .attr_value = {
                                               .len = sizeof(temp_data),
                                               .handle = param->read.handle,
                                               .value = temp_data
                                           }
                                       });
            break;
        }

        // 处理写请求（客户端修改睡眠间隔）
        case ESP_GATTS_WRITE_EVT: {
            if (!param->write.is_prep) {  // 非准备写
                ESP_LOGI(TAG, "Write config request, len: %d", param->write.len);
                if (param->write.len == 4) {
                    // 从客户端数据中解析新的睡眠时长（4字节 -> uint32_t）
                    uint32_t new_sleep = *(uint32_t*)param->write.value;
                    if (new_sleep >= 1000 && new_sleep <= 60000) {  // 限制范围：1~60秒
                        sleep_duration = new_sleep;
                        nvs_save_sleep_config();  // 保存到NVS
                    } else {
                        ESP_LOGW(TAG, "Invalid sleep duration (must be 1000~60000ms)");
                    }
                }
            }
            break;
        }

        // 处理通知配置（客户端开启/关闭通知）
        case ESP_GATTS_CCCD_EVT: {
            uint16_t cccd_val = *(uint16_t*)param->cccd.value;
            if (cccd_val == ESP_GATT_CCCD_NOTIFY_EN) {
                ESP_LOGI(TAG, "Notify enabled, send current temperature");
                // 发送当前温度数据
                esp_ble_gatts_send_indicate(gatts_if, param->cccd.conn_id,
                                           param->cccd.handle, sizeof(temp_data),
                                           temp_data, false);
                conn_id = param->cccd.conn_id;  // 记录连接ID
            } else {
                ESP_LOGI(TAG, "Notify disabled");
                conn_id = 0;
            }
            break;
        }

        // 断开连接后重新广播
        case ESP_GATTS_DISCONNECT_EVT:
            ESP_LOGI(TAG, "Device disconnected, restart advertising");
            esp_ble_gap_start_advertising(&adv_params);
            conn_id = 0;
            break;

        default:
            break;
    }
}

// -------------------------- BLE GAP 回调（广播/连接） --------------------------
static esp_ble_adv_data_t adv_data = {
    .include_name = true,
    .include_txpower = true,
    .service_uuid_len = sizeof(uint16_t),
    .p_service_uuid = (uint8_t*)&ENV_SERVICE_UUID,  // 广播环境服务UUID
    .flag = ESP_BLE_ADV_FLAG_GEN_DISC | ESP_BLE_ADV_FLAG_BREDR_NOT_SUPPORTED,
};

static esp_ble_adv_params_t adv_params = {
    .adv_int_min = 0x800,  // 广播间隔：0x800 * 0.625ms = 1000ms
    .adv_int_max = 0x1000, // 最大间隔：2000ms（降低广播频率以省电）
    .adv_type = ADV_TYPE_IND,
    .channel_map = ADV_CHNL_ALL,
    .adv_filter_policy = ADV_FILTER_ALLOW_SCAN_ANY_CON_ANY,
};

static void gap_event_handler(esp_gap_ble_cb_event_t event, esp_ble_gap_cb_param_t *param) {
    switch (event) {
        case ESP_GAP_BLE_ADV_START_COMPLETE_EVT:
            if (param->adv_start_cmpl.status == ESP_BT_STATUS_SUCCESS) {
                ESP_LOGI(TAG, "Advertising started");
            } else {
                ESP_LOGE(TAG, "Advertising start failed");
            }
            break;
        case ESP_GAP_BLE_CONNECT_EVT:
            ESP_LOGI(TAG, "Device connected, stop advertising");
            esp_ble_gap_stop_advertising();  // 连接后停止广播（省电）
            break;
        default:
            break;
    }
}

// -------------------------- 低功耗配置 --------------------------
static void configure_low_power() {
    // 1. 关闭 unused 外设时钟
    periph_module_disable(PERIPH_UART0_MODULE);  // 若不使用UART调试，可关闭
    periph_module_disable(PERIPH_SPI_MODULE);

    // 2. 配置深度睡眠唤醒源（定时唤醒）
    esp_sleep_enable_timer_wakeup(sleep_duration * 1000);  // 单位：us

    // 3. 释放GPIO引脚（避免漏电）
    gpio_deep_sleep_hold_dis();
}

// -------------------------- 主函数 --------------------------
void app_main(void) {
    // 1. 初始化NVS（读取睡眠配置）
    esp_err_t ret = nvs_flash_init();
    if (ret == ESP_ERR_NVS_NO_FREE_PAGES || ret == ESP_ERR_NVS_NEW_VERSION_FOUND) {
        ESP_ERROR_CHECK(nvs_flash_erase());
        ret = nvs_flash_init();
    }
    ESP_ERROR_CHECK(ret);
    nvs_load_sleep_config();

    // 2. 初始化蓝牙（仅启用BLE）
    ESP_ERROR_CHECK(esp_bt_controller_mem_release(ESP_BT_MODE_CLASSIC_BT));
    esp_bt_controller_config_t bt_cfg = BT_CONTROLLER_INIT_CONFIG_DEFAULT();
    ESP_ERROR_CHECK(esp_bt_controller_init(&bt_cfg));
    ESP_ERROR_CHECK(esp_bt_controller_enable(ESP_BT_MODE_BLE));
    ESP_ERROR_CHECK(esp_bluedroid_init());
    ESP_ERROR_CHECK(esp_bluedroid_enable());

    // 3. 注册GATT和GAP回调
    ESP_ERROR_CHECK(esp_gatts_register_callback(gatts_event_handler));
    ESP_ERROR_CHECK(esp_gatts_app_register(0));  // 注册GATT应用
    ESP_ERROR_CHECK(esp_ble_gap_register_callback(gap_event_handler));

    // 4. 配置设备名称和广播
    esp_ble_gap_set_device_name(DEVICE_NAME);
    esp_ble_gap_config_adv_data(&adv_data);

    // 5. 模拟工作：运行5秒后进入深度睡眠
    vTaskDelay(pdMS_TO_TICKS(5000));

    // 6. 配置低功耗并进入深度睡眠
    ESP_LOGI(TAG, "Entering deep sleep for %ums", sleep_duration);
    configure_low_power();
    esp_deep_sleep_start();
}